using Kickball.Step1;
using Kickball.Step2;
using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;
using UnityEngine;

namespace Kickball.Step4
{
    [UpdateBefore(typeof(TransformSystemGroup))]
    public partial struct PlayerMovementSystem_Job : ISystem
    {
        [BurstCompile]
        public void OnCreate(ref SystemState state)
        {
            state.RequireForUpdate<Execute.PlayerMovement_Job>();
            state.RequireForUpdate<Config>();
        }

        [BurstCompile]
        public void OnUpdate(ref SystemState state)
        {
            var config = SystemAPI.GetSingleton<Config>();
            var obstacleQuery = SystemAPI.QueryBuilder().WithAll<LocalTransform, Obstacle>().Build();

            //输入
            float horizontal = Input.GetAxis("Horizontal");
            float vertical = Input.GetAxis("Vertical");
            float3 input = new float3(horizontal, 0, vertical) * SystemAPI.Time.DeltaTime * config.PlayerSpeed;

            if (input.Equals(float3.zero)) return;

            float playerRadius = 0.5f;
            float minDist = config.ObstacleRadius + playerRadius;
            float minDistSq = minDist * minDist;

            var playerMovementJob = new PlayerMovementJob()
            {
                //查询所有障碍并传入
                Obstacles = obstacleQuery.ToComponentDataArray<LocalTransform>(state.WorldUpdateAllocator),
                Input = input,
                MinDistSq = minDistSq,
            };

            //并行执行
            playerMovementJob.ScheduleParallel();
        }
    }

    [BurstCompile]
    [WithAll(typeof(Player))]
    public partial struct PlayerMovementJob : IJobEntity
    {
        [ReadOnly] public NativeArray<LocalTransform> Obstacles;
        public float3 Input;
        public float MinDistSq;

        void Execute(ref LocalTransform transform)
        {
            float3 pos = transform.Position + Input; //计算位移
            foreach (var obstacle in Obstacles)
            {
                if (math.distancesq(obstacle.Position, pos) < MinDistSq) //障碍碰撞
                {
                    pos = transform.Position;
                    break;
                }
            }

            transform.Position = pos;
        }
    }
}